#include "stdafx.h"
#include "cppflibinc.h"


using namespace cppflib;
using namespace cppflib::os;
using namespace cppflib::util;

static void TestAllocate()
{
   cppmempool::MemPoolWrap memPool;      // first mem pool
   assert(memPool.GetNodesCount() == 0);

   int * pInt = new (FMP_NEWPTR) int[4];
   char * pChar = (char*)::MRP_Calloc(8, sizeof(char)); // this will go to debug pool
   assert(memPool.GetNodesCount() == 1);

   cppmempool::UnlinkFromPool(pChar);  // unlink has no effect

   cppmempool::MemPoolWrap memPool2;  // second mem pool
   assert(!memPool2.AddMemBlock(pInt));    // can't be added since it is already attached to a pool
   assert(memPool2.GetNodesCount() == 0); 

   cppmempool::UnlinkFromPool(pInt);  // unlink from its attaching pool
   cppmempool::UnlinkFromPool(pInt);  // unlink once more will have no effect
   assert(memPool2.AddMemBlock(pInt));
   assert(memPool.GetNodesCount() == 0); 
   assert(memPool2.GetNodesCount() == 1);

   assert(memPool2.AddMemBlock(pInt));  // can't add more than once but will return true
   assert(memPool2.GetNodesCount() == 1);
   cppmempool::Retain(pInt);
   
   // close pool explicitly
   memPool2.Close();  // pInt will go to debug pool since it has one more ref count
   
   int *pInt2 = new int[4];  // in debug pool
   delete [] pInt2;          // release from debug pool

   //
   // finally, pInt and pChar still hang around without releasing (memory leak)
   //
#ifdef _DEBUG
   assert(::MRP_GetDebugPoolNodesCount() >= 2);
#endif

   //
   // Comment the following so that MRP_GlobalFinish will detect a memory leak
   //
   cppmempool::Release(pInt);
   cppmempool::Release(pChar);
}


/**
 *  To demonstrate memory leak
 */
/*
static void TestAllocate2()
{
   cppmempool::MemPoolWrap memPool;
   int count = 10;
   CFString * pStr = new CFString[count];
   
   for (int i = 0; i < count; ++i)
      pStr[i].Format(_S(">>  %d"), i);

   CFString * pStr2 = new CFString("hello");
}
*/

static void TestAllocate3()
{
   cppmempool::MemPoolWrap memPool;

   CFString * pStr2;

   // throwing exception in new will cause program to quit under Linux
   try {
      pStr2 = new CFString[10];
   }
   catch (const char * pErr) {
      CFString s(pErr);
      debug::Print(debug::DL_DEBUG, _S("err = %s\r\n"), static_cast<pcwstr_t>(s));
   }
}

static void TestAllocate4()
{
   cppmempool::MemPoolWrap memPool;

   const int NUM = 6;
   CFString **pStrArr = new (FMP_NEWPTR) CFString* [NUM];
   for (int i = 0; i < NUM; ++i) {
      pStrArr[i] = new CFString();
      pStrArr[i]->Format(_S("hello %d !!!"), i + 1);
   }
}

static int testfunc(int a, int b)
{
   return a + b;
}

class MyObject : public BaseObject
{
public:
   int testAdd(int a, int b)
   {
      return a + b + 2;
   }
};


static BaseFuncPtr2T<int, int, int> * __TestFuncPtrs()
{
   cppmempool::MemPoolWrap memPool;

   debug::Print(_S("Testing function pointer objects...\r\n"));

   MyObject *pNewObj = new MyObject();
   FuncPtr2T<int, int, int> func1(&testfunc);
   MemberFuncPtr2T<MyObject, int, int, int> * objFunc1 =  // make objFunc1 has a weak reference to pNewObj
                                    new MemberFuncPtr2T<MyObject, int, int, int>(pNewObj, &MyObject::testAdd, true);
   cppmempool::UnlinkFromPool(objFunc1);
   BaseFuncPtr2T<int, int, int> *pFunc = &func1;

   assert((*pFunc)(2, 4) == 6);

   pFunc = objFunc1;

   assert((*pFunc)(2, 4) == 8);

   return objFunc1;
}

static void TestFuncPtrs()
{
   cppmempool::MemPoolWrap memPool;

   try {
      BaseFuncPtr2T<int, int, int> * pFunc = __TestFuncPtrs();
      cppmempool::AddToCurPool(pFunc);
      (*pFunc)(2, 4);
   }
   catch (exceptions::BaseException &e) {
      debug::Print(debug::DL_DEBUG, _S("err = %s\r\n"), e.GetMsg());
   }
}

void TestAllocation(void)
{
   debug::Print(_S("Testing allocation...\r\n"));
   TestAllocate();
   //TestAllocate2();
   TestAllocate3();
   TestAllocate4();
   TestFuncPtrs();
}
